package br.ufpb.di.ppgi.persistencia.pagination;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * Design Patter: Adapter - Encapsula um {@link PagedList} dentro de um adaptador com
 * as mesma funcionalidades escritas em portugues, para facilitar o uso na view.<br/> 
 * <br/>
 * Encapsula o resultado parcial de uma consulta, que retrata uma pagina especifica,
 * guardando todas as propriedades de paginação.
 * @author Tomaz Lavieri
 * @see PagedList#toVersaoEmPortugues()
 * @param <T> O tipo de objeto que esta {@link PagedList} guarda
 */
public class ListaPaginada<T> implements Serializable {
	private static final long serialVersionUID = -7154463978142414742L;
	private final PagedList<T> wrap;
	private final List<Page> pages;
	
	/**
	 * Quantidade padrão de páginas a serem exibidas no cabeçalho de paginação.
	 * @see #getMaxPages()
	 */
	public static int getQtdPaginasPadrao() {
		return PagedList.getDefaultMaxPages();
	}
	/**
	 * Altera a quantidade padrão de páginas a serem exibidas no cabeçalho de paginação,
	 * esta alteração sera refletida em todas as proximas instancias criadas, alterando
	 * seus valores iniciais.<br/>
	 * <br/>
	 * Para alterações em uma instância especifica use {@link #setMaximoDePaginas(int)}
	 * @param defaultMaxPages a nova quantidade padrão
	 * @see #setMaximoDePaginas(int)
	 */
	public static void setQtdPaginasPadrao(int defaultMaxPages) {
		PagedList.setDefaultMaxPages(defaultMaxPages);
	}
	
	public ListaPaginada(PagedList<T> pagedList) {
		this.wrap = pagedList;
		this.pages = new ArrayList<Page>();
	}
	/**
	 * A lista de objetos <tt>T</tt> continadas nesta página.
	 */
	public List<T> getLista() {
		return wrap.getList();
	}
	/**
	 * O número de resultados totais da consultas, mostrando a quantidade
	 * contida em todas aspáginas.
	 */
	public int getQtdResultados() {
		return wrap.getNumberOfResults();
	}
	/**
	 * A quantidade máxima de resultados exibidas em uma única página.
	 */
	public int getQtdMaxima() {
		return wrap.getMaxResultOnPage();
	}
	/**
	 * O número da página atual (a contagem de páginas inicia em 1)
	 */
	public int getPagina() {
		return wrap.getPage();
	}
	/**
	 * O número de páginas totais da consulta.
	 */
	public int getQtdPaginas() {
		return wrap.getNumberOfPages();
	}
	/**
	 * O número do primeiro resultado desta página, portanto os resultados
	 * desta página vão de {@link #startedNumber} até {@link #finishedNumber}
	 */
	public int getPrimeiroDaPagina() {
		return wrap.getStartedNumber();
	}
	/**
	 * O número do último resultado desta página, portanto os resultados
	 * desta página vão de {@link #startedNumber} até {@link #finishedNumber}
	 */
	public int getUltimoDaPagina() {
		return wrap.getFinishedNumber();
	}
	/**
	 * Informa se a página corrente é a última página da consulta. 
	 */
	public boolean isUltimaPagina() {
		return wrap.isLastPage();
	}
	/**
	 * Infroma se a página corrente é a primeira página da consulta.
	 */
	public boolean isPrimeiraPagina(){
		return wrap.isFirstPage();
	}
	/**
	 * Informa a quantidade de resultados exibidos nesta página.
	 */
	public int getQtdNaPagina() {
		return wrap.getListSize();
	}
	/**
	 * Informa se a página esta vazia. 
	 */
	public boolean isPaginaVazia() {
		return wrap.isEmpty();
	}
	/**
	 * Informa se a página corrente está fora do alcance para consulta, ou seja,
	 * verifica se a página é maior que o número de paginas da consulta,
	 * se {@link #page} > {@link #numberOfPages}.
	 */
	public boolean isPaginaInexistente() {
		return wrap.isOutOfRange();
	}
	/**
	 * Método de comodidade, que pode ser usado na view para informar a base 
	 * do link para gerar a páginação. Por padrão {@link #getBase()} retorna
	 * <tt>null</tt>, exceto se na lógica após uma consulta seja usado o método
	 * {@link #setBase(String)}.
	 * @return a base para o link de páginação
	 */
	public String getBase() {
		return wrap.getBase();
	}
	/**
	 * Método de comodidade, define a base para o link de paginação usada na view.
	 * @param base a base para o link de páginação
	 */
	public ListaPaginada<T> setBase(String base) {
		wrap.setBase(base);
		return this;
	}
	
	/**
	 * Quantidade de páginas a serem exibidas no cabeçalho de paginação.
	 * @see #setDefaultMaxPages(int)
	 */
	public int getMaximoDePaginas() {
		return wrap.getMaxPages();
	}
	/**
	 * Altera a quantidade de páginas a serem exibidas no cabeçalho de paginação,
	 * esta alteração sera refletida apenas para esta uma instância especifica
	 * @param maxPages a nova quantidade
	 * @see #setDefaultMaxPages(int)
	 */
	public ListaPaginada<T> setMaximoDePaginas(int maxPages) {
		wrap.setMaxPages(maxPages);
		return this;
	}
	
	/**
	 * Retorna a lista de páginas a serem exibidas no cabeçalho de paginação.
	 */
	public List<Page> getPages() {
		if (pages.isEmpty()) {
			synchronized (this) {
				if (pages.isEmpty()) {
					for (int i = getPaginaInicial(); i <= getPaginaFinal(); i++) 
						pages.add(new Page(i));
				}
			}
		}
		return pages;
	}
	
	public class Page {
		private final int n;
		Page(int n) {
			this.n = n;
		}
		public int getNumero() {
			return n;
		}
		public boolean isAtual() {
			return n == getPagina();
		}
		@Override
		public String toString() {
			return String.valueOf(n);
		}
	}
	
	/**
	 * Indica em que numero as paginas exibidas no cabelho iniciam.
	 */
	public int getPaginaInicial() {
		return wrap.getPagesStartAt();
	}
	/**
	 * Indica em que numero as paginas exibidas no cabelho iniciam.
	 */
	public int getPaginaFinal() {
		return wrap.getPagesFinishAt();
	}
	
	/**
	 * Indica se ha' mais página(s) a esquerda, alem das exibidas.
	 */
	public boolean isMaisPaginasAntes() {
		return wrap.isMorePagesBefore();
	}
	/**
	 * Indica se ha' mais página(s) a direita, alem das exibidas.
	 */
	public boolean isMaisPaginasDepois() {
		return wrap.isMorePagesAfter();
	}
	
	/**
	 * Retorna para a versao em ingles.
	 */
	public PagedList<T> toEnglishVersion() {
		return wrap;
	}
}
